PROCEDURE SETTRACESITES;
CONST RET=13;
VAR I:INTEGER;
  CH:CHAR;
BEGIN
  WRITELN;
  WRITELN('Enter trace site numbers (-1 terminates)');
  REPEAT
    WRITE('>');
    READLN(I);
    IF (I>=0) AND (I<=100) THEN
      BEGIN
        IF I IN DBTRACESET THEN WRITE(' ON')
                           ELSE WRITE(' OFF');
        WRITE('   S(et or R(eset ?');
        REPEAT
          READ(CH);
        UNTIL CH IN ['R','S'];
        IF CH='S' THEN
          DBTRACESET:=DBTRACESET+[I]
        ELSE
          DBTRACESET:=DBTRACESET-[I];
      END;
    WRITELN;
  UNTIL I<0;
  REPEAT
    WRITE('L(ower Bound=', TRACELB, '  U(pper Bound=', TRACEUB, '  <RET>');
    READ(CH);
    IF EOLN THEN CH:=CHR(RET) ELSE WRITELN;
    IF CH = 'L' THEN
      BEGIN
        WRITE('  LB:');
        READLN(TRACELB);
      END
    ELSE
      IF CH = 'U' THEN
        BEGIN
          WRITE('  UB:');
          READLN(TRACEUB);
        END;
  UNTIL CH = CHR(RET);
END (*SETTRACESITES*);
  
PROCEDURE TRACEWA(TRACENUM:INTEGER; WI:DBWRKINDEX);
VAR I,L,P:INTEGER;
  DONE:BOOLEAN;
  S:STRING[10];
BEGIN
  DONE:=FALSE;
  WHILE (TRACENUM IN DBTRACESET) AND (NOT DONE) DO
    BEGIN
      WRITELN;
      WITH WRKTABLE[WI] DO
        BEGIN
          WRITELN('TRACE # ', TRACENUM, '  WA:', WI,
                  '  TOS:', TOS,
                  '  WSIZE:', WSIZE,
                  '  SPACEINUSE:', SPACEINUSE);
          IF WIB = NIL THEN
            WRITELN('  WIB = NIL ****')
          ELSE
            FOR L:=0 TO TOS DO
              WITH WIB^[L] DO
                BEGIN
                  WRITE('  L:', L, ':  OFFSET:', OFFSET, '  LEVEL:');
                  CASE LEVEL OF
                    GROUPT: WRITE('GROUP');
                    RECORDT: WRITE('RECORD');
                    FIELDT: WRITE('FIELD');
                    NONET: WRITE('NONE')
                  END (*CASE*);
                  WRITELN('  DESCR#:', DESCRIPTORNUM);
(*$L #5:DBUXXX.LST.TEXT*)
                  
                END (*WITH WIB*);
          P:=TRACELB;
          IF WA = NIL THEN
            WRITELN('    WA = NIL')
          ELSE
            WHILE P <= TRACEUB DO
              BEGIN
                WRITE('    ', P:3, ':');
                FOR I:=0 TO 9 DO
                  BEGIN
(*$R-*)
                    WRITE(WA^[P]:4);
(*$R+*)
                    P:=P+1;
                  END;
                WRITELN;
              END;
          WRITELN('<RET> CONTINUES; "D<RET>" TOGGLES DEBUGGING');
          WRITE(' "T<RET>" TO CHANGE TRACE SITES:');
          READLN(S);
          DONE:=TRUE;
          IF LENGTH(S) > 0 THEN
            IF S[1] = 'T' THEN
              BEGIN
                SETTRACESITES;
                WRITE('<RET> CONTINUES; R<RET> RE-DISPLAYS');
                READLN(S);
                IF LENGTH(S) > 0 THEN
                  DONE:=(S[1] <> 'R');
              END
            ELSE
              IF S[1] = 'D' THEN
                DEBUGGING:=NOT DEBUGGING;
        END (*WITH WRKTABLE*);
    END (*DEBUGGING*);
END (*TRACEWA*);

PROCEDURE DBSHOWERROR(*S:STRING; ERRNUM: DBERRTYPE*);
CONST
  RET=13;
  CAN=24;
  ESC=27;
VAR CH:CHAR;
BEGIN
  IF (ERRNUM<>0) OR DEBUGGING THEN
    (*temporary substitute for display of actual message*)
    BEGIN
      WRITELN;
      WRITELN('DBERROR # ', ERRNUM, ' IN ', S);
      WRITELN(' <RET> CONTINUES, <ESC> ABORTS, <CAN> TERMINATES');
      WRITELN(' "T" TO CHANGE TRACE SITES');
      REPEAT
        READ(CH);
        IF EOLN THEN CH:=CHR(RET);
      UNTIL CH IN [CHR(RET), CHR(CAN), CHR(ESC), 'T'];
      IF CH = CHR(CAN) THEN
        EXIT(PROGRAM);
      IF CH = CHR(ESC) THEN
        HALT;
      IF CH = 'T' THEN SETTRACESITES;
    END;
END (*DBSHOWERROR*);

PROCEDURE DBITEMINFO(*WI:DBWRKINDEX; VAR LEVEL:DBLEVELTYPE;
            VAR ITEMNUM,OFFSET,DESCRIPTORNUM:INTEGER; VAR NAME:STRING*);
TYPE
  TRICKPTR =
    RECORD CASE BOOLEAN OF
      TRUE: (R:RECDESPTR);
      FALSE:(G:GRPDESPTR)
    END;
VAR FP:FLDDESPTR;
  TP:TRICKPTR;
  NILMSG:STRING[25];
  DPTR:INTEGER;
  PAB:PACKED ARRAY[0..255] OF BYTE;
  
  PROCEDURE EXTRACTNAME(TP:TRICKPTR; DPTR:INTEGER);
  BEGIN
    (*get the name field length into PAB[DPTR]*)
    MOVELEFT(TP.R^, PAB, DPTR+1);
    (*this time transfer the name*)
    MOVELEFT(TP.R^, PAB, DPTR+PAB[DPTR]);
    MOVELEFT(PAB[DPTR], NAME, PAB[DPTR]);
    (*convert to string*)
    DELETE(NAME, LENGTH(NAME), 1);
  END (*EXTRACTNAME*);
  
BEGIN (*DBITEMINFO*)
  WITH WRKTABLE[WI] DO
    BEGIN
      LEVEL:=WIB^[TOS].LEVEL;
      ITEMNUM:=WIB^[TOS].ITEMNUM;
      OFFSET:=WIB^[TOS].OFFSET;
      DESCRIPTORNUM:=WIB^[TOS].DESCRIPTORNUM;
      NILMSG:='NIL Descriptor Pointer';
      WITH WIB^[TOS] DO
        BEGIN
          IF (DESCRIPTORNUM < 0) THEN
            NAME:='Uninitialized Descriptor Number'
          ELSE
            CASE LEVEL OF
              FIELDT:
                BEGIN
                  FP:=ACTIVEFIELDS[DESCRIPTORNUM];
                  IF FP=NIL THEN
                    NAME:=NILMSG
                  ELSE
                    NAME:=FP^.NAME;
                END (*FIELDT:*);
              RECORDT:
                BEGIN
                  TP.R:=ACTIVERECORDS[DESCRIPTORNUM];
                  IF TP.R = NIL THEN
                    NAME:=NILMSG
                  ELSE
                    BEGIN
                      DPTR:=7 + TP.R^.LASTFLDLINK;
                      EXTRACTNAME(TP,DPTR);
                    END;
                END (*RECORDT:*);
              GROUPT:
                BEGIN
                  TP.G:=ACTIVEGROUPS[DESCRIPTORNUM];
                  IF TP.G = NIL THEN
                    NAME:=NILMSG
                  ELSE
                    BEGIN
                      DPTR:=2 + TP.G^.RECLINK;
                      EXTRACTNAME(TP,DPTR);
                    END;
                END (*GROUPT:*)
            END (*CASES*);
        END (*WITH WIB^*);
    END (*WITH*);
END (*DBITEMINFO*);
  
  (*$L-*)
  
FUNCTION CHECKHEAP(SIZE:INTEGER):BOOLEAN;
VAR MA:INTEGER;
BEGIN
  MA:=MEMAVAIL + MEMAVAIL;
  CHECKHEAP:=(MA<0) (* i.e. more than 32767 *)
              OR (MA>SIZE);
END (*CHECKHEAP*);

FUNCTION MAX(X,Y:INTEGER):INTEGER;
BEGIN
  IF X>Y THEN MAX:=X ELSE MAX:=Y;
END;

FUNCTION CHECKWORKAREA(WI:DBWRKINDEX; SIZE:INTEGER):DBERRTYPE;
BEGIN
  WITH WRKTABLE[WI] DO
    IF (WA=NIL) OR (WIB=NIL) THEN
      CHECKWORKAREA:=8 (*workarea not open*)
    ELSE
      IF WSIZE<>SIZE THEN
        CHECKWORKAREA:=2
      ELSE
        CHECKWORKAREA:=0;
END (*CHECKWORKAREA*);

FUNCTION HEAPALLOCATE(SIZE:PAGEPTR):DBERRTYPE;
VAR
    P1:ONEWORDPTR;
    P64:WAPTR;
BEGIN
  IF CHECKHEAP(SIZE) THEN
    BEGIN
      WHILE SIZE >= 64 DO
        BEGIN
          NEW(P64);
          SIZE:=SIZE-64;
        END;
      IF ODD(SIZE) THEN
        SIZE:=SIZE+1;
      WHILE SIZE>0 DO
        BEGIN
          NEW(P1);
          SIZE:=SIZE-2;
        END;
      HEAPALLOCATE:=0;
    END
  ELSE
    HEAPALLOCATE:=1; (*insufficient memory*)
END (*HEAPALLOCATE*);

PROCEDURE ZEROWORKAREA(*WI:DBWRKINDEX*);
(*unprotected -- call checkworkarea if in doubt*)
VAR I:INTEGER;
BEGIN
  WITH WRKTABLE[WI] DO
    BEGIN
      FILLCHAR(WA^,WSIZE,CHR(0));
      FOR I:=0  TO LASTWRKSTACKSLOT DO
        WITH WIB^[I] DO
          BEGIN
            OFFSET:=0;
            LEVEL:=NONET;
            DESCRIPTORNUM:=-1;
            ITEMNUM:=-1;
          END;
      WITH WIB^[0] DO
        BEGIN
          LEVEL:=GROUPT;
          OFFSET:=0;
          ITEMNUM:=0;
        END;
      SPACEINUSE:=0;
      TOS:=0;
    END (*WITH*);
END (*ZEROWORKAREA*);

FUNCTION NEXTLEVEL(LVL:DBLEVELTYPE):DBLEVELTYPE;
BEGIN
  IF LVL=NONET THEN
    NEXTLEVEL:=NONET
  ELSE
    IF LVL=FIELDT THEN
      NEXTLEVEL:=GROUPT
    ELSE
      NEXTLEVEL:=SUCC(LVL);
END (*NEXTLEVEL*);

FUNCTION MOVETAIL(DESTINATION:DBWRKINDEX; DELTA:INTEGER;
                  OFFSET:PAGEPTR):DBERRTYPE;
(*service routine for data transfer functions. shifts tail of workarea
  after checking whether requested shift is legal *)
BEGIN
  MOVETAIL:=0;
  WITH WRKTABLE[DESTINATION] DO
    BEGIN
      TRACEWA(2,DESTINATION);
      IF (SPACEINUSE+DELTA) >= WSIZE THEN
        MOVETAIL:=14 (*insufficient space*)
      ELSE
        IF (OFFSET+DELTA) < 0 THEN
          MOVETAIL:=17 (*attempted negative offset*)
        ELSE
          BEGIN
(*$R-*)
            IF DELTA > 0 THEN
              BEGIN
                MOVERIGHT(WA^[OFFSET], WA^[OFFSET+DELTA], SPACEINUSE-OFFSET);
                FILLCHAR(WA^[OFFSET],DELTA,CHR(0));
              END
            ELSE
              IF DELTA < 0 THEN
                MOVELEFT(WA^[OFFSET], WA^[OFFSET+DELTA], SPACEINUSE-OFFSET);
            SPACEINUSE:=SPACEINUSE+DELTA;
            IF DELTA < 0 THEN
              FILLCHAR(WA^[SPACEINUSE], -DELTA, CHR(0));
(*$R+*)
          END;
      TRACEWA(3,DESTINATION);
    END (*WITH*);
END (*MOVETAIL*);

FUNCTION LINKVALUE(WA:WAPTR; OFFSET: PAGEPTR):PAGEPTR;
VAR B1:BYTE;
BEGIN
(*$R-*)
  B1:=WA^[OFFSET];
  IF B1 < LINKESCAPE THEN
    LINKVALUE:=B1
  ELSE
    LINKVALUE:=(B1-LINKESCAPE+1)*LINKESCAPE+WA^[OFFSET+1];
(*$R+*)
END (*LINKVALUE*);

PROCEDURE SAVEBIGLINK(DESTINATION:DBWRKINDEX; NEWLINK:INTEGER; OFFSET:PAGEPTR);
BEGIN
  WITH WRKTABLE[DESTINATION] DO
    BEGIN
(*$R-*)
      IF NEWLINK < LINKESCAPE THEN
        WA^[OFFSET]:=NEWLINK
      ELSE
        BEGIN
          WA^[OFFSET]:=(NEWLINK DIV LINKESCAPE)+(LINKESCAPE-1);
          WA^[OFFSET+1]:=(NEWLINK MOD LINKESCAPE);
        END;
(*$R+*)
    END;
END (*SAVEBIGLINK*);

FUNCTION LINKDELTA(DESTINATION:DBWRKINDEX; DELTA:INTEGER;
                                           OFFSET:PAGEPTR):DBERRTYPE;
(*add delta to the link at offset*)
VAR B1,OLDLINK,NEWLINK:INTEGER;
  CHOP:
    PACKED RECORD CASE BOOLEAN OF
      TRUE: (INT:INTEGER);
      FALSE: (LB:BYTE; HB:BYTE)
    END;

BEGIN
  LINKDELTA:=0;
  TRACEWA(4,DESTINATION);
  WITH WRKTABLE[DESTINATION] DO
    BEGIN
      OLDLINK:=LINKVALUE(WA,OFFSET);
      IF ((OFFSET+OLDLINK+DELTA) >= WSIZE) OR ((OLDLINK+DELTA) < 0) THEN
        LINKDELTA:=16 (*out of range*)
      ELSE
        BEGIN
          NEWLINK:=OLDLINK+DELTA;
          IF NEWLINK > 4079 (* (256-LINKESCAPE)*256+(LINKESCAPE-1) *) THEN
            LINKDELTA:=18 (* too large to be expressed as a link *)
          ELSE
            IF OLDLINK < LINKESCAPE THEN (* one byte *)
              BEGIN
                IF NEWLINK < LINKESCAPE THEN (*also one byte*)
  (*$R-*)
                  WA^[OFFSET]:=NEWLINK
                ELSE
                  BEGIN
                    NEWLINK:=NEWLINK+1; (* one more byte for 2-byte link *)
                    DBSHOWERR('LINKDELTA#1', MOVETAIL(DESTINATION,1,OFFSET));
                    SAVEBIGLINK(DESTINATION,NEWLINK,OFFSET);
                  END;
              END (*OLDLINK < LINKESCAPE*)
            ELSE
              BEGIN (*OLDLINK >= LINKESCAPE i.e. 2 bytes*)
                IF (NEWLINK < LINKESCAPE) THEN
                  BEGIN
                    IF NEWLINK > 1 THEN
                      NEWLINK:=NEWLINK-1; (*newlink 1-byte, oldlink was 2*)
                                          (*however, cannot go < 1*)
                    DBSHOWERR('LINKDELTA#2', MOVETAIL(DESTINATION,-1,
                           OFFSET + 1(*avoid tromping on previous data*)));
                    WA^[OFFSET]:=NEWLINK;
  (*$R+*)
                  END
                ELSE (*both old and new are 2 bytes*)
                  SAVEBIGLINK(DESTINATION,NEWLINK,OFFSET);
              END (*OLDLINK >= LINKESCAPE*);
        END (* (OFFSET+DELTA) < WSIZE *);
    END (*WITH WRKTABLE*);
  TRACEWA(5,DESTINATION);
END (*LINKDELTA*);

PROCEDURE FIXLINKS(DESTINATION:DBWRKINDEX; STACKCELL:TOSRANGE; DELTA:INTEGER);
(*following a change in item contents, all enclosing levels must have 
  links corrected*)
VAR ISTACK:INTEGER;
BEGIN
  WITH WRKTABLE[DESTINATION] DO
    FOR ISTACK:=STACKCELL DOWNTO 0 DO
      WITH WIB^[ISTACK] DO
        DBSHOWERR('FIXLINKS', LINKDELTA(DESTINATION,DELTA,OFFSET));
  TRACEWA(16,DESTINATION);
END (*FIXLINKS*);
              
FUNCTION LINKSIZE(LINKV:INTEGER):INTEGER;
BEGIN
  IF LINKV >= LINKESCAPE THEN LINKSIZE:=2
                         ELSE LINKSIZE:=1;
END (*LINKSIZE*);

PROCEDURE STEPLINK(WI:DBWRKINDEX);
(*advance offset at current level to step over a link-like item (either
  link or tag*)
BEGIN
  WITH WRKTABLE[WI] DO
    WITH WIB^[TOS] DO
      OFFSET:=OFFSET+1+ORD(LINKVALUE(WA,OFFSET) >= LINKESCAPE);
END (*STEPLINK*);

PROCEDURE NEXTLINK(WA:WAPTR; VAR OFFSET:PAGEPTR; VAR ITEMNUM:INTEGER);
(*advance offset to next location on list*)
VAR LINKV:INTEGER;
BEGIN
  LINKV:=LINKVALUE(WA,OFFSET);
  (*combine this guy and linkvalue call into one external proc*)
  IF LINKV > 0 THEN
    BEGIN
      OFFSET:=OFFSET+LINKV;
      ITEMNUM:=ITEMNUM+1;
    END;
END (*NEXTLINK*);

PROCEDURE SETDESCRIPTORNUM(WI:DBWRKINDEX);
(*gets descriptor number for field # ITEMNUM from list in record descriptor*)
(* group descriptor from enclosing field or tag*)
(* record descriptor from group*)
VAR RP:RECDESPTR;
  GP:GRPDESPTR;
  FP:FLDDESPTR;
  LINKV:INTEGER;
BEGIN
  WITH WRKTABLE[WI] DO
    CASE WIB^[TOS].LEVEL OF
      FIELDT:
        BEGIN (*refer to record's list of descriptor pointers*)
          RP:=ACTIVERECORDS[WIB^[TOS-1].DESCRIPTORNUM];
          WITH RP^ DO
            IF (((LASTFLDLINK-1) DIV SIZEOF(FLDREF))-2) < WIB^[TOS].ITEMNUM THEN
              (*Note: one item only (i.e. itemnum=0) goes with
                LASTFLDLINK = 5 if FLDREF is 2 bytes; end of list is one
                FLDREF entry with value of zero as stopper*)
              WIB^[TOS].DESCRIPTORNUM:=-1 (*no such field*)
            ELSE
(*$R-*)
              WITH WIB^[TOS] DO
                DESCRIPTORNUM:=RP^.FLDREF[ITEMNUM].FDNUM;
(*$R-*)
        END;
      GROUPT:
        (*all groups are tagged*)
        (*descriptor number is tag value at page level*)
        IF TOS=0 THEN
          WITH WIB^[TOS] DO
            BEGIN
              LINKV:=LINKVALUE(WA,OFFSET);
              DESCRIPTORNUM:=LINKVALUE(WA,(OFFSET+LINKSIZE(LINKV)));
            END
        ELSE
          BEGIN (*get from parent field descriptor*)
            FP:=ACTIVEFIELDS[WIB^[TOS-1].DESCRIPTORNUM];
            WITH WIB^[TOS] DO
              DESCRIPTORNUM:=FP^.FLDREF;
          END;
      RECORDT:
        BEGIN (*record is tagged if group specifies mixed records*)
          GP:=ACTIVEGROUPS[WIB^[TOS-1].DESCRIPTORNUM];
          WITH WIB^[TOS] DO
            WITH GP^ DO
              IF RECLINK > ONEITEMRECLINK THEN (*mixed*)
                BEGIN
                  LINKV:=LINKVALUE(WA,OFFSET);
                  (*get the tag*)
                  DESCRIPTORNUM:=LINKVALUE(WA,OFFSET+LINKSIZE(LINKV));
                END
              ELSE
                DESCRIPTORNUM:=RECNUM[0];
        END (*RECORDT:*);
    END (*CASES*);
END (*SETDESCRIPTORNUM*);


(*TRAVERSAL PRIMITIVES*)
FUNCTION DBHOME(*WI:DBWRKINDEX):DBERRTYPE*);
(*zero out workstack for the workarea, except for its initial location*)
VAR I:INTEGER;
BEGIN
  WITH WRKTABLE[WI] DO
    BEGIN
      IF WA=NIL THEN
        DBHOME:=8 (* workarea not open *)
      ELSE
        BEGIN
          FOR I:=1 TO TOS DO
            WITH WIB^[I] DO
              BEGIN
                OFFSET:=0;
                LEVEL:=NONET;
                DESCRIPTORNUM:=-1;
                ITEMNUM:=-1;
              END;
          WITH WIB^[0] DO
            BEGIN
              OFFSET:=0;
              ITEMNUM:=0;
              IF DBTYPECHECK THEN SETDESCRIPTORNUM(WI);
            END;
          TOS:=0;
        END (* WA <> NIL *);
    END (*WITH WRKTABLE*);
  TRACEWA(6,WI);
END (*DBHOME*);

FUNCTION DBNEXT(*WI:DBWRKINDEX):DBERRTYPE*);
(*move to head of next linked item*)
VAR RP:RECDESPTR;
  BEFOREITEM,DUMMY:INTEGER;
BEGIN
  DBNEXT:=0;
  TRACEWA(7,WI);
  WITH WRKTABLE[WI] DO
    WITH WIB^[TOS] DO
      BEGIN
        BEFOREITEM:=ITEMNUM;
        IF LEVEL = FIELDT THEN
          BEGIN
            RP:=ACTIVERECORDS[WIB^[TOS-1].DESCRIPTORNUM];
            IF RP = NIL THEN
              DBNEXT:=32
            ELSE
              WITH RP^ DO
                BEGIN
                  IF ITEMNUM < FIRSTLITEMNUM THEN
                    BEGIN
                      ITEMNUM:=ITEMNUM+1;
                      IF ITEMNUM = FIRSTLITEMNUM THEN
                        (*transition from fixed to variable fields*)
                        NEXTLINK(WA,OFFSET,DUMMY);
                    END
                  ELSE
                    NEXTLINK(WA,OFFSET,ITEMNUM);
                END (*WITH RP^*);
          END (*LEVEL=FIELDT*)
        ELSE
          (*all items assumed to be linked & all lists stopped with nul*)
          NEXTLINK(WA,OFFSET,ITEMNUM);
        IF BEFOREITEM = ITEMNUM THEN
          DBNEXT:=27 (*can't find any more*)
        ELSE
          IF DBTYPECHECK THEN SETDESCRIPTORNUM(WI);
      END;
  TRACEWA(8,WI);
END (*DBNEXT*);

FUNCTION DBHEAD(*WI:DBWRKINDEX):DBERRTYPE*);
(*move to head of list at current level*)
VAR LINKV:INTEGER;
  RP:RECDESPTR;
  PARENTOFFSET:PAGEPTR;
BEGIN
  WITH WRKTABLE[WI] DO
    BEGIN
      IF TOS > 0 THEN
        BEGIN
          PARENTOFFSET:=WIB^[TOS-1].OFFSET;
          LINKV:=LINKVALUE(WA,PARENTOFFSET);
          WITH WIB^[TOS] DO
            BEGIN
              OFFSET:=PARENTOFFSET+LINKSIZE(LINKV);
              IF LEVEL = RECORDT THEN (*step over parent group's tag*)
                STEPLINK(WI);
            END;
        END
      ELSE
        (*global group level - point to head of page*)
        WIB^[TOS].OFFSET:=0;
      WIB^[TOS].ITEMNUM:=0;
      IF DBTYPECHECK THEN SETDESCRIPTORNUM(WI);
    END (*WITH WRKTABLE*);
  TRACEWA(30,WI);
END (*DBHEAD*);

FUNCTION DBTAIL(*WI:DBWRKINDEX):DBERRTYPE*);
(*point to link position following last non-nul item at current level*)
VAR RP:RECDESPTR;
  BEFOREITEMNUM:INTEGER;
BEGIN
  WITH WRKTABLE[WI] DO
    WITH WIB^[TOS] DO
      BEGIN
        BEFOREITEMNUM:=ITEMNUM;
        REPEAT
          NEXTLINK(WA,OFFSET,ITEMNUM);
        UNTIL LINKVALUE(WA,OFFSET)=0;
        IF LEVEL = FIELDT THEN
          BEGIN
            RP:=ACTIVERECORDS[WIB^[TOS-1].DESCRIPTORNUM];
            IF RP = NIL THEN
              DBTAIL:=32
            ELSE
              WITH RP^ DO
                IF BEFOREITEMNUM < FIRSTLITEMNUM THEN
                  ITEMNUM:=ITEMNUM + (FIRSTLITEMNUM-BEFOREITEMNUM-1);
          END (*LEVEL=FIELDT*);
        SETDESCRIPTORNUM(WI);
      END (*WITH WIB*);
  TRACEWA(29,WI);
END (*DBTAIL*);


